import { acceptHMRUpdate, defineStore, storeToRefs } from 'pinia'
import { store } from '../index'
import { toggleClass, removeClass } from '@/utils/domUtil'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import { decodeAES, encodeAES } from '@/utils/aesRsa'
import { cloneDeep } from 'lodash-es'
import { useAppStoreWithOut } from '@/store/modules/app'
import { useKeepAliveStoreWithOut } from '@/store/modules/keepAlive'
import { useUserStoreWithOut } from '@/store/modules/user'
import { setPageTitle, findMenuById, routerWhiteList } from '@/utils/routerHelper'
import { SystemMenuTypeEnum } from '@/enums/systemEnums'
import router from '@/router/index'

export const useTagCacheStore = defineStore('tagCache', () => {
  const { wsLocal, wsSession } = useCache()

  const appStore = useAppStoreWithOut()
  const { systemConfig } = storeToRefs(appStore)
  const keepAliveStore = useKeepAliveStoreWithOut()
  const { variables } = useDesign()

  // 标签栏所有标签
  const tagList: any = ref([])
  /**
   * 固定标签缓存规则：系统确定的固定标签，不缓存在fixedTagList中，只有用户设置的固定标签需要被缓存，两者固定后，其数据字段isFixed均为true
   * 通过判断isFixed字段为true，以及是否缓存在fixedTagList中，来判断是系统固定标签，还是用户固定标签
   **/
  const fixedTagList: any = ref([])

  // 获取默认缓存标签
  const getAllTagCache = () => {
    if (wsSession.getItem(CACHE_KEY.USER_ALL_TAG)) {
      tagList.value = decodeAES(wsSession.getItem(CACHE_KEY.USER_ALL_TAG))
    } else {
      tagList.value = []
    }
  }

  // 设置默认标签缓存
  const setAllTagCache = () => {
    if (systemConfig.value.isTagCache) {
      wsSession.setItem(CACHE_KEY.USER_ALL_TAG, encodeAES(tagList.value))
    }
  }

  // 移除所有缓存标签
  const removeAllTagCache = () => {
    tagList.value = []
    if (systemConfig.value.isTagCache) {
      wsSession.removeItem(CACHE_KEY.USER_ALL_TAG)
    }
  }

  // 获取固定标签缓存
  const getFixedTagCache = () => {
    if (wsLocal.getItem(CACHE_KEY.USER_FIXED_TAG)) {
      fixedTagList.value = decodeAES(wsLocal.getItem(CACHE_KEY.USER_FIXED_TAG))
    } else {
      fixedTagList.value = []
    }
  }

  // 设置固定标签缓存
  const setFixedTagCache = () => {
    wsLocal.setItem(CACHE_KEY.USER_FIXED_TAG, encodeAES(fixedTagList.value))
  }

  // 移除固钉标签
  const removeFixedTagCache = () => {
    fixedTagList.value = []
    wsLocal.removeItem(CACHE_KEY.USER_FIXED_TAG)
  }

  // 用户设置标签固定
  const userSetTagFixed = path => {
    fixedTagList.value.push(path)
    setFixedTagCache()
    const currentRouter = tagList.value.filter(item => {
      return item.path === path
    })
    if (currentRouter.length > 0) {
      const toRoute = {
        path: currentRouter[0].path,
        meta: currentRouter[0].meta
      }
      toRoute.meta.isFixed = true
      updateTagMeta({ value: toRoute })
    }
  }

  // 用户取消标签固定
  const userCancelTagFixed = path => {
    if (fixedTagList.value && fixedTagList.value.length > 0) {
      fixedTagList.value = fixedTagList.value.filter(item => {
        return item !== path
      })
      setFixedTagCache()
      const currentRouter = tagList.value.filter(item => {
        return item.path === path
      })
      const toRoute = {
        path: currentRouter[0].path,
        meta: currentRouter[0].meta
      }
      toRoute.meta.isFixed = false
      updateTagMeta({ value: toRoute })
    }
  }

  // 动态添加标签栏路由信息
  const dynamicRouteTag = value => {
    // 获取被缓存的标签页数据
    if (!value.name || (value.name && routerWhiteList.login.includes(value.name))) return
    const userStore = useUserStoreWithOut()
    const { menus } = storeToRefs(userStore)
    const menu = findMenuById(menus.value, value.meta.id as number | string)
    const hasValue = tagList.value.some(item => {
      return item.path === value.fullPath
    })
    const tagRoute: any = {
      path: '',
      name: '',
      meta: {}
    }
    tagRoute.path = value.fullPath
    tagRoute.name = value.name
    tagRoute.meta = cloneDeep(value.meta)
    tagRoute.meta.breadcrumb = menu.meta.breadcrumb
    if (hasValue) {
      updateTagMeta({ value: tagRoute })
    } else {
      // 标签缓存中不存在当前路由，判断当前路由是否需要在标签栏显示，如需要则添加到标签缓存中，showTag:0 表示不在标签栏显示，否则需要在标签栏显示
      if (value.meta.showTag) {
        tagOperateHandle({ mode: 'push', value: tagRoute })
      }
    }
  }

  // 删除动态标签页
  const deleteDynamicTag = (route, router, currentPath: any, mode?: string, toPath?: string) => {
    // 存放被删除的缓存路由
    let delAliveRouteList: any = []
    // 获取当前所在标签页在标签页缓存数据中的索引值，通过索引值以及删除类型，对数据进行删除操作
    const valueIndex: number = tagList.value.findIndex((item: any) => {
      return item.path === currentPath
    })
    let isCurrentTagFixed = false
    tagList.value.forEach(item => {
      if (item.path === currentPath) {
        isCurrentTagFixed = item.meta.isFixed
      }
    })
    // 根据当前mode类型，执行标签页缓存数据操作方法
    if (mode === 'other') {
      // 删除其他路由
      delAliveRouteList = tagList.value.filter((item, index) => {
        return !item.meta.isFixed && index !== valueIndex
      })
      tagOperateHandle({ mode: 'equal', value: valueIndex })
    } else if (mode === 'left') {
      // 删除左侧路由
      delAliveRouteList = tagList.value.filter((item, index) => {
        return !item.meta.isFixed && index < valueIndex
      })
      tagOperateHandle({ mode: 'left', value: valueIndex })
    } else if (mode === 'right') {
      // 删除右侧路由
      delAliveRouteList = tagList.value.filter((item, index) => {
        return !item.meta.isFixed && index > valueIndex
      })
      tagOperateHandle({ mode: 'right', value: valueIndex })
    } else if (mode === 'all') {
      // 删除所有路由
      delAliveRouteList = tagList.value.filter(item => {
        return !item.meta.isFixed
      })
      tagOperateHandle({ mode: 'all' })
    } else {
      // 删除当前路由
      // 从当前匹配到的路径中删除
      delAliveRouteList = tagList.value.filter((item, index) => {
        return !item.meta.isFixed && index === valueIndex
      })
      tagOperateHandle({ mode: 'current', value: valueIndex })
    }
    // 在标签页缓存数据做了删除处理后，还需要提取数据中最后一个路由信息，用于做当前展示路由页面
    const currentRouteFuc = tagOperateHandle({ mode: 'slice', router: router })
    const keepAliveNameList: any = []
    tagList.value.forEach(item => {
      if (item.meta.showTag && item.meta.showTag > 1) {
        if (!keepAliveNameList.includes(item.name)) {
          keepAliveNameList.push(item.name)
        }
      }
    })

    // 删除缓存路由
    keepAliveStore.delAliveRoutes(delAliveRouteList, keepAliveNameList)
    // 当前路由页面是点击事件依据的标签路由（右键点击的标签路由或是下拉框事件时的当前路由）
    if (currentPath === route.fullPath) {
      // 删除的是当前路由左侧、右侧、其它的标签路由，此时当前路由不会发生变化
      if (mode === 'left' || mode === 'right' || mode === 'other') return
      // 当前标签页是非固定标签页时，才会出现全部、当前情况被删除当前标签页，此时需要跳转到最后一个路由
      if (!isCurrentTagFixed) {
        nextTick(() => {
          if (toPath) {
            router.push(toPath)
          } else {
            if (currentRouteFuc) {
              if (tagList.value.length === 0) {
                router.push('/redirect' + currentRouteFuc()[0].path)
              } else {
                router.push(currentRouteFuc()[0].path)
              }
            }
          }
        })
      }
    } else {
      // 这里主要针对右键菜单不是在当前路由上激活，会发生将当前路由删除的情况
      // 如果标签页缓存数据不存在了，则直接返回
      if (!tagList.value.length) return
      // 否则将当前激活的路由找出
      const isHasActiveTag = tagList.value.some(item => {
        return item.path === route.fullPath
      })
      // 如果当前激活的路由不存在（被删除）则跳转到最后一个缓存的标签页
      if (currentRouteFuc) {
        !isHasActiveTag && router.push(currentRouteFuc()[0].path)
      }
    }
  }

  // 标签操作
  const tagOperateHandle = data => {
    switch (data.mode) {
      // 关闭其他
      case 'equal':
        tagList.value = tagList.value.filter((item, index) => {
          return item.meta.isFixed || index === data.value
        })
        setAllTagCache()
        break
      // 关闭左侧
      case 'left':
        tagList.value = tagList.value.filter((item, index) => {
          return item.meta.isFixed || index >= data.value
        })
        setAllTagCache()
        break
      // 关闭右侧
      case 'right':
        tagList.value = tagList.value.filter((item, index) => {
          return item.meta.isFixed || index <= data.value
        })
        setAllTagCache()
        break
      // 关闭当前
      case 'current':
        tagList.value = tagList.value.filter((_item, index) => {
          return index !== data.value
        })
        setAllTagCache()
        break
      // 关闭所有
      case 'all':
        tagList.value = tagList.value.filter(item => {
          return item.meta.isFixed
        })
        setAllTagCache()
        break
      // 添加标签数据
      case 'push':
        const tagVal = data.value
        // 判断tag是否已存在:
        const tagHasExits = tagList.value.some(tag => {
          return tag.path === tagVal?.path
        })
        // tag已经存在，并且showTag值为0或1，说明不需要多开标签页，标签页已存在，也不需要再添加，此时直接返回
        if (tagHasExits && (!tagVal?.meta?.showTag || tagVal?.meta?.showTag === 1)) return
        // 如果标签不存在，并且其相同name的路由已存在，同时该页面又不允许多开，则不能添加新的标签，而需要将原有相同name路由标签的数据替换成新标签的数据
        if (!tagHasExits && tagList.value.filter(e => e.name === tagVal.name).length > 0 && tagVal?.meta?.showTag === 1) {
          const currentTagList = cloneDeep(tagList.value)
          currentTagList.forEach(item => {
            if (item.name === tagVal.name) {
              item.meta = tagVal?.meta
              item.path = tagVal?.path
            }
          })
          tagList.value = currentTagList
        }
        // 如果标签不存在，并且相同name路由已经存在，且多开页面是允许的，则需要进行进一步逻辑判断
        if (!tagHasExits && tagList.value.filter(e => e.name === tagVal.name).length > 0 && tagVal?.meta?.showTag > 1) {
          const meta = tagVal?.meta

          const dynamicLevel = meta?.showTag ?? -1
          if (dynamicLevel > 1 && !tagHasExits) {
            // dynamicLevel动态路由可打开的数量
            const realName = tagVal.name
            // 获取到已经打开的动态路由数, 判断是否大于dynamicLevel
            if (tagList.value.filter(e => e.name === realName).length >= dynamicLevel) {
              // 关闭第一个
              const index = tagList.value.findIndex(item => item.name === realName)
              index !== -1 && tagList.value.splice(index, 1)
            }
          }
          // 删除已缓存的详情路由，并将新的进行缓存

          const tagIndex = tagList.value.findIndex(item => item.path === tagVal?.path)
          if (tagIndex !== -1) {
            tagList.value.splice(tagIndex, 1, data.value)
          }
        }
        // 标签不存在且同name路由也不存在、或者标签不存在且同name路由存在且多开标签页功能开启时
        if ((!tagHasExits && tagList.value.filter(e => e.name === tagVal.name).length === 0) || (!tagHasExits && tagList.value.filter(e => e.name === tagVal.name).length > 0 && tagVal?.meta?.showTag > 1)) {
          tagList.value.push(data.value)
          setAllTagCache()
        }
        break
      // 关闭当前需要返回标签栏最后一条数据作为当前路由页面
      case 'slice':
        return () => {
          const toRouter: any = []
          if (tagList.value.length === 0) {
            const userStore = useUserStoreWithOut()
            const { menus } = storeToRefs(userStore)
            if (menus.value.length > 0) {
              const menu = menus.value[0]
              let path = null
              if (menu.meta.type === SystemMenuTypeEnum.DIR) {
                path = menu.redirect
              } else {
                path = menu.path
              }
              const toRoute = {
                path: path,
                name: menu.name,
                meta: menu.meta
              }
              toRouter.push(toRoute)
            } else {
              router.push('/404')
            }
          } else {
            toRouter.push(tagList.value.slice(-1)[0])
          }
          return toRouter
        }
    }
  }

  // 更新标签信息
  const updateTagMeta = data => {
    tagList.value.forEach(item => {
      if (item.path === data.value.path) {
        item.meta = data.value.meta
        if (fixedTagList.value.length > 0 && fixedTagList.value.includes(data.value.path)) {
          item.meta.isFixed = true
        }
      }
    })
    setAllTagCache()
  }

  // 标签页刷新
  const refreshPage = (route, router) => {
    // 执行刷新按钮的动画效果
    toggleClass(true, variables.namespace + '-refresh-rotate', document.querySelector('.' + variables.namespace + '-btn-refresh'))
    const { fullPath } = unref(route)
    // 替换路由，到重定向页面，重定向页面会自动跳转到需要跳转的页面
    router.replace('/redirect' + fullPath)
    // 移除刷新按钮的动画效果
    setTimeout(() => {
      const htmlElement = document.querySelector('.' + variables.namespace + '-btn-refresh') as HTMLElement | null
      if (htmlElement) {
        removeClass(htmlElement, variables.namespace + '-refresh-rotate')
      }
    }, 600)
  }

  // 更新标签标题
  const updateTagTitle = (title, route) => {
    const { t } = useI18n() // 国际化
    const userStore = useUserStoreWithOut()
    const { menus } = storeToRefs(userStore)
    const menu = findMenuById(menus.value, route.meta.id as number | string)
    const toRoute = {
      path: route.fullPath,
      meta: route.meta
    }
    toRoute.meta.breadcrumb = menu.meta.breadcrumb
    toRoute.meta.title = title + '-' + t('router', route.meta.title)
    updateTagMeta({ value: toRoute })
  }

  // 获取当前路由的meta数据
  const getCurrentRouterMeta = path => {
    let currentMeta = {}
    tagList.value.forEach(item => {
      if (item.path === path) {
        currentMeta = item.meta
      }
    })
    return currentMeta
  }

  // 更新标签和页面标题
  const updateTitle = (title, route) => {
    updateTagTitle(title, route)
    setPageTitle(getCurrentRouterMeta(route.fullPath))
  }

  return {
    tagList,
    fixedTagList,
    tagOperateHandle,
    dynamicRouteTag,
    deleteDynamicTag,
    updateTagMeta,
    getAllTagCache,
    setAllTagCache,
    removeAllTagCache,
    userSetTagFixed,
    userCancelTagFixed,
    getFixedTagCache,
    setFixedTagCache,
    removeFixedTagCache,
    refreshPage,
    updateTagTitle,
    getCurrentRouterMeta,
    updateTitle
  }
})

// pinia默认不使用热更新，容易报错 ReferenceError: Cannot access ‘...‘ before initialization
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useTagCacheStore, import.meta.hot))
}

// router初始化优先于pinia，在router中使用pinia，需要先进行注册
export const useTagCacheStoreWithOut = () => {
  return useTagCacheStore(store)
}
